import {defineComponent, h, Transition} from "vue";

interface HTMLExpandElement extends HTMLElement {
    _parent?: Node | ParentNode | HTMLElement | null;
    _initialStyle?: {
        width?: string | null
        transition?: string
        overflow?: any
        padding?: any
        position?: any
        top?: any
        left?: any
        transformOrigin?: any
        webkitTransformOrigin?: any
    };
}


export default defineComponent({
    name: "ICollapseYTransition",
    props: {
        duration: {
            type: Number,
            default: 300,
        },
        origin: {
            type: String,
            default: "top center 0",
        },
        leaveAbsolute: {
            type: Boolean,
            default: false,
        },
        hideOnLeave: {
            type: Boolean,
            default: false,
        },
    },
    setup(props, {slots}) {
        const transition = `${props.duration}ms width cubic-bezier(.25, .8, .50, 1), ${props.duration}ms padding-top cubic-bezier(.25, .8, .50, 1), ${props.duration}ms padding-bottom cubic-bezier(.25, .8, .50, 1)`;

        function onBeforeEnter(el: HTMLExpandElement) {
            el._initialStyle = {
                transition: el.style.transition,
                overflow: el.style.overflow,
                width: el.style.width,
                padding: el.style.padding,
                transformOrigin: el.style.transformOrigin,
                webkitTransformOrigin: el.style.webkitTransformOrigin,
            };
            el.style.transition = transition;
            el.style.transformOrigin = props.origin;
            el.style.webkitTransformOrigin = props.origin;
        }

        function onEnter(el: HTMLExpandElement, done: () => void) {
            requestAnimationFrame(() => {
                el.style.setProperty("transition", "none", "important");
                el.style.overflow = "hidden";
                const offset = `${el.offsetWidth}px`;
                const padding = `${el.style.padding}px`;

                el.style.width = "0";
                el.style.padding = "0";

                void el.offsetWidth; // force reflow

                el.style.transition = transition;

                requestAnimationFrame(() => {
                    el.style.width = offset;
                    el.style.padding = padding;
                });
                setTimeout(() => {
                    done();
                }, props.duration + 10);

            });
        }

        function onAfterEnter(el: HTMLExpandElement) {
            for (let initialStyleKey in el._initialStyle) {
                //@ts-ignore
                el.style[initialStyleKey] = el._initialStyle[initialStyleKey];
            }
            delete el._initialStyle;
        }

        function onLeave(el: HTMLExpandElement, done: () => void) {
            if (props.hideOnLeave) {
                el.style.setProperty("display", "none", "important");
                done();
                return;
            }
            if (props.leaveAbsolute) {
                el._initialStyle = {
                    position: el.style.position,
                    top: el.style.top,
                    left: el.style.left,
                    transition: "",
                    overflow: el.style.overflow,
                    width: el.style["width"],
                    padding: el.style["padding"],
                };

                const paddingLeft = el.style.paddingLeft.split("px")[0];
                const paddingTop = el.style.paddingTop.split("px")[0];
                const {offsetTop, offsetLeft} = el;
                el.style.position = "absolute";
                el.style.top = (offsetTop - Number(paddingTop)) + "px";
                el.style.left = (offsetLeft - Number(paddingLeft)) + "px";
            } else {
                el._initialStyle = {
                    transition: "",
                    overflow: el.style.overflow,
                    width: el.style["width"],
                    padding: el.style["padding"],
                };
            }

            el.style.transition = transition;
            el.style.overflow = "hidden";
            el.style.width = `${el["offsetWidth"]}px`;
            el.style.padding = `${el.style["padding"]}px`;

            requestAnimationFrame(() => {
                el.style["width"] = "0";
                el.style["padding"] = "0";
            });
            setTimeout(() => {
                done();
            }, props.duration + 10);
        }

        function onAfterLeave(el: HTMLExpandElement) {
            if (props.hideOnLeave) {
                return;
            }
            if (props.leaveAbsolute) {
                el.style.position = el._initialStyle?.position;
                el.style.top = el._initialStyle?.top;
                el.style.left = el._initialStyle?.left;
            }
            if (el._initialStyle!.width != null) el.style.width = el._initialStyle!.width;
            if (el._initialStyle!.padding != null) el.style.padding = el._initialStyle!.padding;
        }

        // @ts-ignore
        return () => h(Transition, {
            css: false,
            onBeforeEnter,
            onEnter,
            onAfterEnter,
            onLeave,
            onAfterLeave,
        }, slots.default);
    },
});




